﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;

namespace ZackFlame.IronBrainFuck.JIT
{
    internal static class EmitHelper
    {
        public static void EmitNumber(ILGenerator il, UInt32 number)
        {
            switch (number)
            {
                case 0:
                    il.Emit(OpCodes.Ldc_I4_0);
                    break;
                case 1:
                    il.Emit(OpCodes.Ldc_I4_1);
                    break;
                case 2:
                    il.Emit(OpCodes.Ldc_I4_2);
                    break;
                case 3:
                    il.Emit(OpCodes.Ldc_I4_3);
                    break;
                case 4:
                    il.Emit(OpCodes.Ldc_I4_4);
                    break;
                case 5:
                    il.Emit(OpCodes.Ldc_I4_5);
                    break;
                case 6:
                    il.Emit(OpCodes.Ldc_I4_6);
                    break;
                case 7:
                    il.Emit(OpCodes.Ldc_I4_7);
                    break;
                case 8:
                    il.Emit(OpCodes.Ldc_I4_8);
                    break;
                default:
                    il.Emit(OpCodes.Ldc_I4, (Int32)number);
                    break;
            }
        }

        public static void EmitAdd(ILGenerator il, UInt32 count)
        {
            if (count == 0)
                return;

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldelema, typeof(UInt16));
            il.Emit(OpCodes.Dup);
            il.Emit(OpCodes.Ldind_U2);

            EmitNumber(il, count);

            il.Emit(OpCodes.Add);
            il.Emit(OpCodes.Stobj, typeof(UInt16));
        }

        public static void EmitSub(ILGenerator il, UInt32 count)
        {
            if (count == 0)
                return;

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ldelema, typeof(UInt16));
            il.Emit(OpCodes.Dup);
            il.Emit(OpCodes.Ldind_U2);

            EmitNumber(il, count);

            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Stobj, typeof(UInt16));
        }

        public static void EmitRight(ILGenerator il, UInt32 count)
        {
            if (count == 0)
                return;

            il.Emit(OpCodes.Ldloc_0);

            EmitNumber(il, count);

            il.Emit(OpCodes.Add);
            il.Emit(OpCodes.Stloc_0);
        }

        public static void EmitLeft(ILGenerator il, UInt32 count)
        {
            if (count == 0)
                return;

            il.Emit(OpCodes.Ldloc_0);

            EmitNumber(il, count);

            il.Emit(OpCodes.Sub);
            il.Emit(OpCodes.Stloc_0);
        }
    }
}
